using System;
using System.Collections.Generic;
using System.Text;

using System.Windows;

using System.Reflection;
using System.Runtime.InteropServices;
using System.Runtime;
using System.Runtime.InteropServices.ComTypes;

using System.Windows.Media;
using System.Windows.Media.Imaging;

namespace WPFUtil
{
    class BitmapBuffer
    {
        [DllImport("Kernel32.dll", EntryPoint = "RtlMoveMemory")]
        public static extern void CopyMemory(IntPtr Destination, IntPtr Source, [MarshalAs(UnmanagedType.U4)] int Length);

        private BitmapSource _bitmapImage = null;

        private object _wicImageHandle = null;

        private object _wicImageLock = null;

        private uint _bufferSize = 0;

        private IntPtr _bufferPointer = IntPtr.Zero;

        private uint _stride = 0;

        private int _width;

        private int _height;

        public BitmapBuffer(BitmapSource Image)
        {
            
            _bitmapImage = Image;

            
            _bitmapImage.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, new System.Windows.Threading.DispatcherOperationCallback(delegate
            {
                
                _width = _bitmapImage.PixelWidth;
                _height = _bitmapImage.PixelHeight;
                return null;
            }), null);

            
            SetWICHandle();

           
            SetBufferInfo();
        }

        public IntPtr BufferPointer
        {
            get
            {
                
                SetBufferInfo();
                return  _bufferPointer;
            }
        }


        public uint BufferSize
        {
            get{return _bufferSize;}
        }

        public uint Stride
        {
            get { return _stride; }
        }

        private void SetBufferInfo()
        {
            int hr = 0;

            
            Type wicBitmapNativeMethodsClass = Type.GetType("MS.Win32.PresentationCore.UnsafeNativeMethods+WICBitmap, PresentationCore, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35");

            
            MethodInfo[] info = wicBitmapNativeMethodsClass.GetMethods(BindingFlags.Static | BindingFlags.NonPublic);
            
            
            MethodInfo lockmethod = info[0];

            Int32Rect rect = new Int32Rect();

            rect.Width = _width;
            rect.Height = _height;

            object[] args = new object[] { _wicImageHandle, rect, 2, _wicImageHandle };

            hr = (int)lockmethod.Invoke(null, args);

            _wicImageLock = args[3];

            Type wicLockMethodsClass = Type.GetType("MS.Win32.PresentationCore.UnsafeNativeMethods+WICBitmapLock, PresentationCore, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35");

            MethodInfo[] lockMethods = wicLockMethodsClass.GetMethods(BindingFlags.Static | BindingFlags.NonPublic);

            MethodInfo getStrideMethod = lockMethods[0];

            args = new object[] { _wicImageLock, _stride };

            getStrideMethod.Invoke(null, args);

            _stride = (uint)args[1];

            MethodInfo getBufferMethod = lockMethods[1];

            args = new object[] { _wicImageLock, _bufferSize, _bufferPointer };

            hr = (int)getBufferMethod.Invoke(null, args);

            _bufferSize = (uint)args[1];
            _bufferPointer = (IntPtr)args[2];

            DisposeLockHandle();
        }

        private void DisposeLockHandle()
        {
            MethodInfo close = _wicImageLock.GetType().GetMethod("Close");
            MethodInfo dispose = _wicImageLock.GetType().GetMethod("Dispose");

            close.Invoke(_wicImageLock, null);
            dispose.Invoke(_wicImageLock, null);
       }

        private void SetWICHandle()
        {

            Type bmpType = typeof(BitmapSource);

            FieldInfo fInfo = bmpType.GetField("_wicSource", 
                                               BindingFlags.NonPublic | BindingFlags.Instance);

            _wicImageHandle = fInfo.GetValue(_bitmapImage);
        }

    }
}
